#pragma once

#include <glib.h>
#include <srtp2/srtp.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <mutex>
#include <list>
#include <arpa/inet.h>

using namespace std;

typedef enum dtls_role
{
    DTLS_ROLE_ACTPASS = -1,
    DTLS_ROLE_SERVER,
    DTLS_ROLE_CLIENT,
} dtls_role;

typedef enum dtls_state
{
    DTLS_STATE_FAILED = -1,
    DTLS_STATE_CREATED,
    DTLS_STATE_TRYING,
    DTLS_STATE_CONNECTED,
} dtls_state;

class WIceAgent;

/* Helper struct to keep the filter state */
class DtlsBioFilter
{
public:
    DtlsBioFilter()
    {

    }
    ~DtlsBioFilter()
    {
        packets.clear();
    }
    //GList *packets;
    std::list<int> packets;
    std::mutex mutex;
} ;

class WDtlsSrtp
{
public:
    WDtlsSrtp();
    virtual ~WDtlsSrtp();
    static int init(const char* server_pem, const char* server_key);
    static void release();
    static char *getLocalFingerprint();

    bool create(WIceAgent* niceagent, int streamid, int componetid, dtls_role role);
    void destroy();
    void handshake();
    void fdBridge(); // 这个函数就是用于发送dtls握手时加密数据的
    void incomingMsg(char *buf, uint16_t len);
    bool srtpUnprotectRtpBuf(void *srtp_hdr, int *len_ptr);
    bool srtpUnprotectRtcpBuf(void *srtp_hdr, int *len_ptr);

    /*! \brief DTLS role of the gateway for this stream: 1=client, 0=server */
    dtls_role _dtlsRole;
    /*! \brief DTLS state of this component: -1=failed, 0=nothing, 1=trying, 2=connected */
    dtls_state _dtlsState;
    /*! \brief Monotonic time of when the DTLS state has switched to connected */
    gint64 _dtlsConnected;
    /*! \brief SSL context used for DTLS for this component */
    SSL *_ssl;
    /*! \brief Read BIO (incoming DTLS data) */
    BIO *_readBio;
    /*! \brief Write BIO (outgoing DTLS data) */
    BIO *_writeBio;
    /*! \brief Filter BIO (fix MTU fragmentation on outgoing DTLS data, if required) */
    /*应该是由于数据链路层1500字节的限制，需要分包传输，这让_filterBio处理*/
    BIO *_filterBio;
    /*! \brief Whether SRTP has been correctly set up for this component or not */
    gint _srtpValid;
    /*! \brief libsrtp context for incoming SRTP packets */
    srtp_t _srtpIn;
    /*! \brief libsrtp context for outgoing SRTP packets */
    srtp_t _srtpOut;
    /*! \brief libsrtp policy for incoming SRTP packets */
    srtp_policy_t _remotePolicy;
    /*! \brief libsrtp policy for outgoing SRTP packets */
    srtp_policy_t _localPolicy;
    /*! \brief Mutex to lock/unlock this libsrtp context */
    std::mutex _srtpMutex;
    /*! \brief Whether this DTLS stack is now ready to be used for messages as well (e.g., SCTP encapsulation) */
    int _ready;
    WIceAgent *_iceAgent;
    int _streamId;
    int _componentId;

private:
    static gchar s_localFingerprint[512];
    static SSL_CTX *s_sslCtx;
    static X509 *s_sslCert;
    static EVP_PKEY *s_sslKey;
    static BIO_METHOD *s_dtlsBioFilterMethods;
    static int s_mtu;
    static const char *s_srtpError[];

    const gchar *getSrtpError(int error);
    const gchar *getDtlsSrtpState(dtls_state state);

    static int dtlsVerifyCallback(int preverify_ok, X509_STORE_CTX *ctx);
    static int dtlsGenerateKeys(X509** certificate, EVP_PKEY** private_key);
    static int dtlsLoadKeys(const char* server_pem, const char* server_key, X509** certificate, EVP_PKEY** private_key);
    static int dtlsBioFilterInit();
    static int dtlsBioFilterWrite(BIO *bio, const char *in, int inl);
    static long dtlsBioFilterCtrl(BIO *bio, int cmd, long num, void *ptr);
    static int dtlsBioFilterNew(BIO *bio);
    static int dtlsBioFilterFree(BIO *bio);
    static void dtlsCallback(const SSL *ssl, int where, int ret);
    static BIO_METHOD *BioDtlsFilter();
};

